home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / gcl-1.000 / gcl-1 / gcl-1.0 / c / NeXTunixsave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-25  |  10.1 KB  |  493 lines

  1. /*
  2.  * unexec for the NeXT Mach environment.
  3.  *
  4.  * Bradley Taylor (btaylor@NeXT.COM) 
  5.  * February 28, 1990
  6.  * 
  7.  * Modified by Noritake Yonezawa (yonezawa@cs.uiuc.edu)
  8.  * July 28, 1991
  9.  * 
  10.  * Modified by Noritake Yonezawa (yone@vcdew25.lsi.tmg.nec.CO.JP)
  11.  * February 16, 1992
  12.  */
  13. #undef __STRICT_BSD__
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <stdarg.h>
  18. #include <mach.h>
  19. #include <sys/loader.h>
  20. #include <sys/file.h>
  21. #include <sys/stat.h>
  22. #include <libc.h>
  23.  
  24. #define CEIL(x,quantum) ((((int)(x))+(quantum)-1)&~((quantum)-1))
  25.  
  26. /* extern struct section *getsectbyname(char *, char *); */
  27. extern const struct section *getsectbyname(
  28.      const char *segname, 
  29.      const char *sectname);
  30.  
  31. #ifndef BIG_HEAP_SIZE
  32. #define BIG_HEAP_SIZE    0x1000000
  33. #endif
  34.  
  35. int                 big_heap = BIG_HEAP_SIZE;
  36.  
  37. char               *mach_maplimit = 0;
  38. char               *mach_brkpt = 0;
  39.  
  40.  
  41. typedef struct region_t {
  42.     vm_address_t address;
  43.     vm_size_t size;
  44.     vm_prot_t protection;
  45.     vm_prot_t max_protection;
  46.     vm_inherit_t inheritance;
  47.     boolean_t shared;
  48.     port_t object_name;
  49.     vm_offset_t offset;
  50. } region_t;
  51.  
  52. char *
  53. my_sbrk(incr)
  54.     int                 incr;
  55. {
  56.     char               *temp, *ptr;
  57.     kern_return_t       rtn;
  58.  
  59.     if (mach_brkpt == 0) {
  60.     if ((rtn = vm_allocate(task_self(), (vm_address_t *) & mach_brkpt,
  61.                    big_heap, 1)) != KERN_SUCCESS) {
  62.         mach_error("my_sbrk(): vm_allocate() failed", rtn);
  63.         return ((char *)-1);
  64.     }
  65.     mach_maplimit = mach_brkpt + big_heap;
  66.     }
  67.     if (incr == 0) {
  68.     return (mach_brkpt);
  69.     } else {
  70.     ptr = mach_brkpt + incr;
  71.     if (ptr <= mach_maplimit) {
  72.         temp = mach_brkpt;
  73.         mach_brkpt = ptr;
  74.         return (temp);
  75.     } else {
  76.         fprintf(stderr, "my_sbrk(): no more memory\n");
  77.         fflush(stderr);
  78.         return ((char *)-1);
  79.     }
  80.     }
  81. }
  82.  
  83. static void
  84. grow(
  85.      struct load_command ***the_commands,
  86.      unsigned *the_commands_len
  87.      )
  88. {
  89.     if (*the_commands == NULL) {
  90.         *the_commands_len = 1;
  91.         *the_commands = malloc(sizeof(*the_commands));
  92.     } else {
  93.         (*the_commands_len)++;
  94.         *the_commands = realloc(*the_commands, 
  95.                     (*the_commands_len *
  96.                      sizeof(**the_commands)));
  97.     }
  98. }
  99.  
  100.  
  101. static void
  102. save_command(
  103.          struct load_command *command,
  104.          struct load_command ***the_commands,
  105.          unsigned *the_commands_len
  106.          )
  107. {
  108.     struct load_command **tmp;
  109.  
  110.     grow(the_commands, the_commands_len);
  111.     tmp = &(*the_commands)[*the_commands_len - 1];
  112.     *tmp = malloc(command->cmdsize);
  113.     bcopy(command, *tmp, command->cmdsize);
  114. }
  115.  
  116. static void
  117. fatal_unexec(char *format, ...)
  118. {
  119.     va_list ap;
  120.  
  121.     va_start(ap, format);
  122.     fprintf(stderr, "unexec: ");
  123.     vfprintf(stderr, format, ap);
  124.     fprintf(stderr, "\n");
  125.     va_end(ap);
  126. }
  127.  
  128. static int
  129. read_macho(
  130.        int fd,
  131.        struct mach_header *the_header,
  132.        struct load_command ***the_commands,
  133.        unsigned *the_commands_len
  134.        )
  135. {
  136.     struct load_command command;
  137.     struct load_command *buf;
  138.     int i;
  139.     int size;
  140.  
  141.     if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
  142.         fatal_unexec("cannot read macho header");
  143.         return (0);
  144.     }
  145.     for (i = 0; i < the_header->ncmds; i++) {
  146.         if (read(fd, &command, sizeof(struct load_command)) != 
  147.             sizeof(struct load_command)) {
  148.               fatal_unexec("cannot read macho load command header");
  149.             return (0);
  150.         }
  151.         size = command.cmdsize - sizeof(struct load_command);
  152.         if (size < 0) {
  153.               fatal_unexec("bogus load command size");
  154.             return (0);
  155.         }
  156.         buf = malloc(command.cmdsize);
  157.         buf->cmd = command.cmd;
  158.         buf->cmdsize = command.cmdsize;
  159.         if (read(fd, ((char *)buf + 
  160.                   sizeof(struct load_command)), 
  161.              size) != size) {
  162.               fatal_unexec("cannot read load command data");
  163.             return (0);
  164.         }
  165.         save_command(buf, the_commands, the_commands_len);
  166.     }
  167.     return (1);
  168. }
  169.  
  170. static int
  171. filldatagap(
  172.         vm_address_t start_address,
  173.         vm_size_t *size,
  174.         vm_address_t end_address
  175.         )
  176. {
  177.     vm_address_t address;
  178.     vm_size_t gapsize;
  179.  
  180.     address = (start_address + *size);
  181.     gapsize = end_address - address;
  182.     *size += gapsize;
  183.     if (vm_allocate(task_self(), &address, gapsize,
  184.             FALSE) != KERN_SUCCESS) {
  185.         fatal_unexec("cannot vm_allocate");
  186.             return (0);
  187.     }
  188.     return (1);
  189. }
  190.  
  191. static int
  192. get_data_region(
  193.         vm_address_t *address,
  194.         vm_size_t *size
  195.         )
  196. {
  197.     region_t region;
  198.     kern_return_t ret;
  199.     struct section *sect;
  200.  
  201.     sect = getsectbyname(SEG_DATA, SECT_DATA);
  202.     region.address = 0;
  203.     *address = 0;
  204.     for (;;) {
  205.         ret = vm_region(task_self(), 
  206.                 ®ion.address, 
  207.                 ®ion.size, 
  208.                 ®ion.protection, 
  209.                 ®ion.max_protection, 
  210.                 ®ion.inheritance,
  211.                 ®ion.shared, 
  212.                 ®ion.object_name, 
  213.                 ®ion.offset);
  214.         if (ret != KERN_SUCCESS || region.address >= mach_maplimit) {
  215.             break;
  216.         }
  217.         if (*address != 0) {
  218.             if (region.address > *address + *size) {
  219.                 if (!filldatagap(*address, size, 
  220.                          region.address)) {
  221.                     return (0);
  222.                 }
  223.             } 
  224.             *size += region.size;
  225.         } else {
  226.             if (region.address == sect->addr) {
  227.                 *address = region.address;
  228.                 *size = region.size;
  229.             } 
  230.         }
  231.         region.address += region.size;
  232.     }
  233.     return (1);
  234. }
  235.  
  236. static char *
  237. my_malloc(
  238.       vm_size_t size
  239.       )
  240. {
  241.     vm_address_t address;
  242.  
  243.     if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
  244.         return (NULL);
  245.     }
  246.     return ((char *)address);
  247. }
  248.  
  249. static void
  250. my_free(
  251.     char *buf,
  252.     vm_size_t size
  253.     )
  254. {
  255.     vm_deallocate(task_self(), (vm_address_t)buf, size);
  256. }
  257.  
  258. static int
  259. unexec_doit(
  260.         int infd,
  261.         int outfd
  262.         )
  263. {
  264.     int i;
  265.     struct load_command **the_commands = NULL;
  266.     unsigned the_commands_len;
  267.     struct mach_header the_header;
  268.     int fgrowth;
  269.     int fdatastart;
  270.     int fdatasize;
  271.     int size;
  272.     int seg;
  273.     struct stat st;
  274.     char *buf;
  275.     vm_address_t data_address;
  276.     vm_size_t data_size, bss_size;
  277.  
  278.     struct segment_command *segment;
  279.     struct section *section;
  280.  
  281.     if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
  282.         return (0);
  283.     }
  284.  
  285.     if (!get_data_region(&data_address, &data_size)) {
  286.         return (0);
  287.     }
  288.  
  289.     /*
  290.      * DO NOT USE MALLOC IN THIS SECTION
  291.      */
  292.     {
  293.         /*
  294.          * Fix offsets
  295.          */
  296.         for (i = 0; i < the_commands_len; i++) {
  297.             switch (the_commands[i]->cmd) {
  298.             case LC_SEGMENT:
  299.                 segment = ((struct segment_command *)
  300.                        the_commands[i]);
  301.                 if (strcmp(segment->segname, SEG_DATA) == 0) {
  302. /*
  303.                         data_address = segment->vmaddr;
  304. */
  305.                     data_size = CEIL(mach_brkpt - data_address, getpagesize());
  306.                     bss_size = mach_maplimit - mach_brkpt;
  307.                     fdatastart = segment->fileoff;
  308.                     fdatasize = segment->filesize;
  309.                     fgrowth = (data_size - 
  310.                            segment->filesize);
  311.                     segment->vmsize = data_size + bss_size;
  312.                     segment->filesize = data_size;
  313.  
  314.                     section = (struct section *) ((char *) (segment + 1));
  315.                     for (seg = 0; seg < segment->nsects; ++seg, ++section) {
  316.                         if (strcmp(section->sectname, SECT_DATA) == 0) {
  317.                                 section->size = data_size;
  318.                         }
  319.                         else if (strcmp(section->sectname, SECT_BSS) == 0) {
  320.                                 section->addr = data_address + data_size;
  321.                                 section->size = bss_size;
  322.                             section->flags = S_ZEROFILL;
  323.                     }
  324.                         else if (strcmp(section->sectname, SECT_COMMON) == 0) {
  325.                                 section->addr = data_address + data_size + bss_size;
  326.                     }
  327.                           }
  328.                 }
  329.                                 if (strcmp(segment->segname, SEG_LINKEDIT) == 0) {
  330.                                         segment->vmaddr += CEIL(fgrowth + bss_size, getpagesize());
  331.                                         segment->fileoff += fgrowth;
  332.                 }
  333.                 break;
  334.             case LC_SYMTAB:
  335.                 ((struct symtab_command *)
  336.                  the_commands[i])->symoff += fgrowth;
  337.                 ((struct symtab_command *)
  338.                  the_commands[i])->stroff += fgrowth;
  339.                 break;
  340.             case LC_SYMSEG:
  341.                 ((struct symseg_command *)
  342.                  the_commands[i])->offset += fgrowth;
  343.                 break;
  344.             default:
  345.                 break;
  346.             }
  347.         }
  348.         
  349.         /*
  350.          * Write header
  351.          */
  352.         if (write(outfd, &the_header, 
  353.               sizeof(the_header)) != sizeof(the_header)) {
  354.             fatal_unexec("cannot write header");
  355.             return (0);
  356.         }
  357.         
  358.         /*
  359.          * Write commands
  360.          */
  361.         for (i = 0; i < the_commands_len; i++) {
  362.             if (write(outfd, the_commands[i], 
  363.                   the_commands[i]->cmdsize) != 
  364.                 the_commands[i]->cmdsize) {
  365.                   fatal_unexec("cannot write commands");
  366.                 return (0);
  367.             }
  368.         }
  369.         
  370.         /*
  371.          * Write original text
  372.          */
  373.         if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
  374.               L_SET) < 0) {
  375.               fatal_unexec("cannot seek input file");
  376.             return (0);
  377.         }
  378.         size = fdatastart - (sizeof(the_header) + 
  379.                      the_header.sizeofcmds);
  380.         buf = my_malloc(size);
  381.         if (read(infd, buf, size) != size) {
  382.             my_free(buf, size);
  383.               fatal_unexec("cannot read input file");
  384.         }
  385.         if (write(outfd, buf, size) != size) {
  386.             my_free(buf, size);
  387.             fatal_unexec("cannot write original text");
  388.             return (0);
  389.         }
  390.         my_free(buf, size);
  391.         
  392.         
  393.         /*
  394.          * Write new data
  395.          */
  396.         if (write(outfd, (char *)data_address, 
  397.               data_size) != data_size) {
  398.             fatal_unexec("cannot write new data");
  399.             return (0);
  400.         }
  401.         
  402.     }
  403.  
  404.     /*
  405.      * OKAY TO USE MALLOC NOW
  406.      */
  407.  
  408.     /*
  409.      * Write rest of file
  410.      */
  411.     fstat(infd, &st);
  412.     if (lseek(infd, fdatasize, L_INCR) < 0) {
  413.         fatal_unexec("cannot seek input file");
  414.         return (0);
  415.     }
  416.     size = st.st_size - lseek(infd, 0, L_INCR);
  417.  
  418.     buf = malloc(size);
  419.     if (read(infd, buf, size) != size) {
  420.         free(buf);
  421.         fatal_unexec("cannot read input file");
  422.         return (0);
  423.     }
  424.     if (write(outfd, buf, size) != size) {
  425.         free(buf);
  426.         fatal_unexec("cannot write reset of file");
  427.         return (0);
  428.     }
  429.     free(buf);
  430.     return (1);
  431. }
  432.  
  433. void
  434. unexec(
  435.        char *outfile,
  436.        char *infile
  437.        )
  438. {
  439.     int infd;
  440.     int outfd;
  441.     char tmpbuf[L_tmpnam];
  442.     char *tmpfile;
  443.  
  444.     infd = open(infile, O_RDONLY, 0);
  445.     if (infd < 0) {
  446.           fatal_unexec("cannot open input file `%s'", infile);
  447.         exit(1);
  448.     }
  449.     
  450.     tmpnam(tmpbuf);
  451.     tmpfile = rindex(tmpbuf, '/');
  452.     if (tmpfile == NULL) {
  453.         tmpfile = tmpbuf;
  454.     } else {
  455.         tmpfile++;
  456.     }
  457.     outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
  458.     if (outfd < 0) {
  459.         close(infd);
  460.         fatal_unexec("cannot open tmp file `%s'", tmpfile);
  461.         exit(1);
  462.     }
  463.     if (!unexec_doit(infd, outfd)) {
  464.         close(infd);
  465.         close(outfd);
  466.         unlink(tmpfile);
  467.         exit(1);
  468.     }
  469.     close(infd);
  470.     close(outfd);
  471.     if (rename(tmpfile, outfile) < 0) {
  472.         unlink(tmpfile);
  473.         fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
  474.         exit(1);
  475.     }
  476. }
  477.  
  478. Lsave()
  479. {
  480.     char    filename[256];
  481.  
  482.     check_arg(1);
  483.     check_type_or_pathname_string_symbol_stream(&vs_base[0]);
  484.     coerce_to_filename(vs_base[0], filename);
  485.  
  486.     _cleanup();
  487.  
  488.     unexec(filename, kcl_self);
  489.  
  490.     exit(0);
  491.     /* no return  */
  492. }
  493.